
#include <iostream>
#include <string>
#include <fstream>

#include "dataset.h"
#include "solutionpool.h"
#include "agentInitSmallTree.h"
#include "agentInitBigTree.h"
#include "agentModCombineTrees.h"
#include "agentModAddRule.h"
#include "agentModAddLeaf.h"
#include "agentDelete.h"

using namespace std;

// Read parameter values
int ROUNDS;
int RUNS_PER_ROUND;
int SEED;
int TARGET_POOL_SIZE;
void readIniValues();


int main()
{
    cout << "------------------------------------------" <<  endl;
    cout << "\n";
    cout << "Agent-Based Decision Tree Construction" << endl;
    cout << "\n";
    system("date"); 
    cout << "\n";
    cout << "------------------------------------------" <<  endl;
    readIniValues();
    srand(SEED);

    cout << "--------- Loading Training Data ----------" << endl;
    dataset* trainSet = new dataset("train.txt", TRAIN_RECORD_COUNT);
    cout << "----------- Done Loading Data ------------" << endl;
    cout << "--------- Loading Test Set Data ----------" << endl;
    dataset* testSet = new dataset("test.txt", TEST_RECORD_COUNT);
    cout << "----------- Done Loading Data ------------" << endl;

    cout << "---------- Optimization Started ----------" << endl;


    solutionpool* thePool = new solutionpool(trainSet, testSet, TARGET_POOL_SIZE);

    // Seed Solution Pool with Initial Solutions
    agentInitSmallTree agentInitSmall(thePool);
    agentInitBigTree agentInitBig(thePool);

    for (int j = 0; j < RUNS_PER_ROUND; ++j)
    {
        switch (rand() % 2)
        {
        case 0:
            agentInitSmall.run();
            break;
        case 1:
            agentInitBig.run();
            break;
        }
    }

    // Instatiate Modification Agents
    agentModAddRule agentAddRule(thePool);
    agentModAddLeaf agentAddLeaf(thePool);
    agentModCombineTrees agentModCombineTree(thePool);

    // Instantiate Deletion Agent
    agentDelete deleteAgent(thePool);

    // Run modification agents
    for (int i = 0; i < ROUNDS; i++)
    {
        for (int j = 0; j < RUNS_PER_ROUND; ++j)
        {
            switch (rand() % 3)
            {
            case 0:
                agentAddRule.run();                    
                break;
            case 1:
                agentAddLeaf.run();                    
                break;
            case 2:
                agentModCombineTree.run();                    
                break;
            }
        }
        cout << "Pruning Solution Pool\n";
        deleteAgent.run();           
    }
    cout << "++++++++++++++++++++++++++++++++++++++++++\n";
    cout << "+              FINAL SOLUTION            +\n";
    cout << "++++++++++++++++++++++++++++++++++++++++++\n";
    thePool->outputBest();
    cout << "++++++++++++++++++++++++++++++++++++++++++\n";
    cout << "--------- Optimization Complete ----------" << endl;
}

void readIniValues()
{
   ifstream inFile("agent.ini");
   string label;

   cout << "--------- Optimization Settings ----------" << endl;
   assert (inFile >> label);
   assert (label == "SEED");
   assert (inFile >> SEED);
   cout << label << "=" << SEED << endl;
 
   assert (inFile >> label);
   assert (label == "ROUNDS");
   assert (inFile >> ROUNDS);
   cout << label << "=" << ROUNDS << endl;
   
   assert (inFile >> label);
   assert (label == "RUNS_PER_ROUND");
   assert (inFile >> RUNS_PER_ROUND);
   cout << label << "=" << RUNS_PER_ROUND << endl;
   
   assert (inFile >> label);
   assert (label == "TARGET_POOL_SIZE");
   assert (inFile >> TARGET_POOL_SIZE);
   cout << label << "=" << TARGET_POOL_SIZE << endl;
   
   assert (inFile >> label);
   assert (label == "MIN_SPLIT_SIZE");
   assert (inFile >> MIN_SPLIT_SIZE);
   cout << label << "=" << MIN_SPLIT_SIZE << endl;

   cout << "------- End Optimization Settings --------" << endl;
   
}

